import { type Nullable } from '~/types/fns'
/**
 * @description 立即执行函数
 * @param fn 被执行函数
 * @param args 被执行函数参数
 * @return 被执行函数返回值
 */
export function call<A extends any[], R>(fn: (...args: A) => R, ...args: A): R {
  return fn.apply(globalThis, args ?? [])
}
/**
 * 尝试执行函数，永远不会抛出异常
 *
 * @description 尝试执行函数，并捕获可能出现的异常，确保不会抛出错误。
 * @param fn 被执行函数 需要执行的函数。
 * @param args 被执行函数参数 传递给函数的参数列表。
 * @returns 被执行函数返回值 函数执行成功时返回函数执行结果，否则返回undefined。
 */
export function tryCall<A extends any[], R>(fn: (...args: A) => R, ...args: A): R | void {
  try {
    return fn.apply(globalThis, args ?? [])
  } catch (e) {
    console.error(e)
  }
}

/**
 * 尝试异步调用函数
 *
 * @param fn 异步函数
 * @param args 传递给异步函数的参数列表
 * @returns 返回异步函数的执行结果，如果执行出错则返回void
 * @template A 传递给异步函数的参数类型列表
 * @template R 异步函数的返回类型
 */
export async function tryAsyncCall<A extends any[], R>(
  fn: (...args: A) => Promise<R>,
  ...args: A
): Promise<R | void> {
  try {
    return await fn.apply(globalThis, args ?? [])
  } catch (err) {
    console.error(err)
  }
}

/**
 * @description 尝试执行函数
 * @param fn 被执行函数
 * @param args 被执行函数参数
 * @return 被执行函数返回值和异常的元组
 */
export function tryCatch<A extends any[], R>(
  fn: (...args: A) => R,
  ...args: A
): [R, Nullable<unknown>] {
  const res: [R, Nullable<unknown>] = [null as unknown as R, null]
  try {
    res[0] = fn.apply(globalThis, args ?? [])
    return res
  } catch (err) {
    res[1] = err
    return res
  }
}

/**
 * 尝试异步执行函数并捕获异常
 *
 * @param fn 需要执行的异步函数
 * @param args 传递给异步函数的参数列表
 * @returns 返回值为一个元组，包含异步函数的返回值和可能抛出的异常。如果函数执行成功，则异常为 null；如果函数执行失败，则返回值为 null，异常为抛出的错误对象。
 * @template A 传递给异步函数的参数类型列表
 * @template R 异步函数的返回类型
 */
export async function tryAsyncCatch<A extends any[], R>(
  fn: (...args: A) => Promise<R>,
  ...args: A
): Promise<[R, Nullable<unknown>]> {
  const res: [R, Nullable<unknown>] = [null as unknown as R, null]
  try {
    res[0] = await fn.apply(globalThis, args ?? [])
    return res
  } catch (err) {
    res[1] = err
    return res
  }
}
